/**
 * 楼层操作
 */
const path = require("path");
const _ = require("lodash");
const chalk = require("chalk");
const INTERFACE = require("../service/INTERFACE");
const FormData = require("form-data");
const fetch = require("../util/fetch");
const { getSetting } = require("../service/setting");
const { readJson, writeFile } = require("../util/fileUtil");
const { createUid } = require("../util/uidUtil");
const {
  readFloors,
  configDataToDataDefinesNodeText,
  readModuleList,
  readEditPropertyJson,
  readConfigData,
  readFloorList,
  saveFloor,
} = require("../service/proxy");
const { FloorChannelType } = require("../common");
// 楼层画布数据文件路径
const floorsFile = path.resolve(process.cwd(), "datas", "floors.json");

/**
 * 生成容器数据结构
 * @param uid 格式：1055531555485799
 * @param containerPosition 默认"content" 可选，"header"
 * @param moduleName 模块名称 备注
 * @param moduleFlag 模块标识 moduleFlag
 * @returns 返回容器数据结构
 */
const generateContainer = ({
  uid,
  containerPosition = "content",
  moduleName,
  moduleFlag,
}) => {
  return {
    borderRadius: 12,
    containerAlias: moduleName,
    containerId: uid,
    containerPosition: containerPosition,
    includeUids: [uid],
    marginBottom: 8,
    marginLeft: 10,
    marginRight: 10,
    marginTop: 0,
    typeCn: moduleName,
    typeCode: moduleFlag,
  };
};

/**
 * 生成楼层数据结构
 * @param uid 格式：1055531555485799
 * @param moduleType 类型， isv 99999 共建 101
 * @param floorHeight 楼层兜底高度
 * @param moduleFlag 模块标识
 * @param floorPosition
 * @param containerType
 * @param middleTemplateId
 * @param moduleId
 * @param moduleName
 * @param configData 楼层上保存的示例配置数据
 * @returns 返回楼层数据结构
 */
const generateFloor = ({
  uid,
  moduleType = FloorChannelType.ISV,
  floorHeight,
  moduleFlag,
  floorPosition = "content",
  containerType = "container",
  middleTemplateId,
  moduleId,
  moduleName,
  configData = {},
}) => {
  const moduleTypeToNumber = Number(moduleType);
  let template = {
    configEmpty: false,
    dsConfig: {
      containerType: containerType,
      editProperty: {
        dataDefines: [],
      },
    },
    floorExtInfo: {
      biSort: false,
      floorHeight: floorHeight,
      moduleFlag: moduleFlag,
      moduleType: moduleTypeToNumber,
    },
    configData: configData,
    floorHeight: floorHeight,
    floorPosition: floorPosition,
    middleTemplateId: middleTemplateId,
    moduleDesignerType: "TERMINATOR",
    moduleFlag: moduleFlag,
    moduleId: moduleId,
    moduleName: moduleName,
    moduleType: moduleTypeToNumber,
    previewUri:
      "//img13.360buyimg.com/imagetools/jfs/t1/144672/21/27031/18516/62593f92E4fcb7223/8727c17395eb0745.png",
    sizeRule: 375,
    uid: uid,
    visible: true,
  };

  return template;
};

// 拉取楼层数据
const onFloorContent = async (ctx) => {
  const floorContent = readFloors(floorsFile);
  // const floorContent = readFloorList()
  ctx.send({ data: { code: 200, data: floorContent } });
};

/**
 * 后端渲染校验模块数据和配置
 * @param ctx
 * @param {*} configJson
 * @param {*} configData
 * @param {*} moduleType 当前渠道，默认isv 9999，现在支持产品化 101
 * @returns
 */
async function renderModuleModular(
  ctx,
  configJson,
  configData,
  moduleType = FloorChannelType.ISV
) {
  const formData = new FormData();
  const param = {
    jsonContent: configJson,
    middleDatas: {
      JSHOP_SDK_MODULE_DATA: configData,
      JSHOP_SDK_CUSTOM_IMAGE: {},
    },
  };
  formData.append("moduleType", moduleType);
  formData.append("jsonContent", JSON.stringify(param.jsonContent));
  formData.append("middleDatas", JSON.stringify(param.middleDatas));
  const debug = getSetting("debug");
  if (debug === true || debug === "true") {
    console.log(
      `renderModuleModular param:\n`,
      chalk.yellow(JSON.stringify(param, null, 2))
    );
  }

  const result = await fetch({
    ctx,
    data: formData,
    method: "POST",
    url: INTERFACE.getModuleRenderData,
  });
  const res = result.data;
  if (res && res.success && res.data) {
    const dataDefines =
      res?.data?.floors[0]?.dsConfig?.editProperty?.dataDefines ?? null;
    if (dataDefines) {
      // 如果是图片热区，并勾选了显示商品价格，这里固定写死返回价格字段 "price": "45.00"。因为后端本地与装修是一套逻辑，本地 mock 的 skuid 拉取不到价格。
      dataDefines.forEach((item) => {
        if (
          item.middleType &&
          item.middleType === "J_PICTURE_HOTSPOT" &&
          item.nodeText.data &&
          item.nodeText.data.length > 0
        ) {
          item.nodeText.data.forEach((hotItem) => {
            hotItem.showSkuPrice === 1 && (hotItem["price"] = "45.00");
          });
        }
      });
      return {
        success: true,
        data: dataDefines,
      };
    } else {
      return {
        success: false,
        error: {
          message: "渲染模块dataDefines数据为空",
        },
      };
    }
  } else {
    return {
      success: false,
      error: {
        message: res.msg || "渲染模块发生错误",
      },
    };
  }
}

/**
 * 增加楼层/保存楼层右侧配置
 * 入参：{
 * moduleId, 模块id（必传）
 * preFloorId, 前一个楼层id,如果不传递放在第一个（店招下面）
 * curFloorId, 当前楼层id（保存配置必传）
 * configData, 保存时配置数据（保存配置必传）
 * configJson, 模块配置项JSON
 * }
 * @param {*} ctx
 * @return 返回单个楼层数据 + resultDatas（保存配置会有）
 */
const onRenderModule = async (ctx) => {
  const body = ctx.request.body;
  const changeQuery = {
    moduleType: FloorChannelType.ISV,
    ...body,
  };
  let { moduleId, preFloorId, curFloorId, configData, configJson, moduleType } =
    changeQuery;
  // TODO: 目前测试出来当configJson数组的长度小于等于21个时，传递过来的是数组类型，长度大于21个时，传递过来的是对象类型
  // 网上看到有一个相似的问题https://segmentfault.com/q/1010000023876312
  // 原因是node服务使用的koa-bodyparser底层是co-body,底层也使用了qs这个库，目前arrayLimit已经改为100
  if (configJson && configJson.length == undefined) {
    configJson = Object.values(configJson);
  }
  if (!moduleId) {
    ctx.send({ data: { code: 300, msg: `入参moduleId不能为空` } });
    return;
  }
  // 现有楼层数据
  const floorContent = readFloors(floorsFile);
  // 现有模块数据
  let list = readModuleList();
  let moduleList = _.get(list, "[0].moduleList", []);
  const module = moduleList.find((item) => {
    return item.moduleId == moduleId;
  });
  if (!module) {
    ctx.send({ data: { code: 300, msg: `不存在moduleId为${moduleId}的模块` } });
    return;
  }
  if (preFloorId != undefined) {
    // 新增楼层
    const uid = createUid();
    const newContainer = generateContainer({
      uid,
      moduleName: module.moduleName,
      moduleFlag: module.moduleFlag,
    });
    const mconfigData = readConfigData(module.moduleFlag);
    let newFloor = generateFloor({
      uid,
      moduleType,
      floorHeight: module.height,
      moduleFlag: module.moduleFlag,
      middleTemplateId: module.middleTemplateId,
      moduleId: module.moduleId,
      moduleName: module.moduleName,
      configData: mconfigData, // 继承模块上的默认配置数据
      // configData: module.configData, // 继承模块上的默认配置数据
    });
    // 基于configData转换editProperty
    // const epJson = readEditPropertyJson(module.moduleFlag)
    // const dataDefines = configDataToDataDefinesNodeText(epJson, mconfigData)

    // 调用后端接口实现获取模块渲染所需数据
    const defaultConfigJson = readEditPropertyJson(module.moduleFlag);
    const result = await renderModuleModular(
      ctx,
      defaultConfigJson,
      mconfigData,
      moduleType
    );
    if (result.success) {
      const dataDefines = result.data;
      // 楼层渲染数据保存到本地server
      _.set(newFloor, "dsConfig.editProperty.dataDefines", dataDefines);
      const index = floorContent.floors.findIndex((floor) => {
        return floor.uid == preFloorId;
      });
      if (index == -1) {
        // 未找到指定楼层
        const headerIndex = floorContent.containers.findIndex((item) => {
          return item.containerPosition == "header";
        });
        if (headerIndex != -1) {
          // 找到店招 插入到店招后面
          floorContent.containers.splice(headerIndex + 1, 0, newContainer);
          floorContent.floors.splice(headerIndex + 1, 0, newFloor);
        } else {
          // 否则放在第一个
          floorContent.containers.unshift(newContainer);
          floorContent.floors.unshift(newFloor);
        }
      } else {
        // 插入到第index后面
        floorContent.containers.splice(index + 1, 0, newContainer);
        floorContent.floors.splice(index + 1, 0, newFloor);
      }
      let returnFloor = {
        containers: [newContainer],
        floors: [newFloor],
        pageSet: {},
      };
      writeFile(floorsFile, JSON.stringify(floorContent, null, 4));
      // 保存modules下对于的floorData.json
      saveFloor(module.moduleFlag, returnFloor);
      ctx.send({ data: { code: 200, data: returnFloor } });
    } else {
      ctx.send({ data: { code: 300, msg: result.error.message } });
    }
  } else if (curFloorId != undefined && configData) {
    // 保存楼层配置
    const index = floorContent.floors.findIndex((floor) => {
      return floor.uid == curFloorId;
    });
    if (index == -1) {
      ctx.send({ data: { code: 300, msg: `不存在uid为${curFloorId}的楼层` } });
      return;
    }
    const container = floorContent.containers[index];
    const floor = floorContent.floors[index];
    floor.configData = configData;
    // // 基于configData转换editProperty
    // const epJson = readEditPropertyJson(module.moduleFlag)
    // const dataDefines = configDataToDataDefinesNodeText(epJson, configData)

    // 调用后端接口实现获取模块渲染所需数据
    const result = await renderModuleModular(
      ctx,
      configJson,
      configData,
      moduleType
    );
    if (result.success) {
      const dataDefines = result.data;
      // 楼层渲染数据保存到本地server
      _.set(floor, "dsConfig.editProperty.dataDefines", dataDefines);
      let returnFloor = {
        containers: [container],
        floors: [floor],
        pageSet: {},
      };
      writeFile(floorsFile, JSON.stringify(floorContent, null, 4));
      // 保存modules下对应的floorData.json
      saveFloor(module.moduleFlag, returnFloor);
      ctx.send({ data: { code: 200, data: returnFloor } });
    } else {
      ctx.send({ data: { code: 300, msg: result.error.message } });
    }
  } else {
    ctx.send({ data: { code: 300, msg: `参数不正确` } });
  }
};

/**
 * 删除楼层
 * @param templateId 整页模板id
 * @param curFloorId 需要删除的楼层id
 * @param {*} ctx
 * @return 返回删除是否成功
 */
const onDeleteFloor = async (ctx) => {
  const body = ctx.request.body;
  const { templateId, curFloorId } = body;
  if (!curFloorId) {
    ctx.send({ data: { code: 300, msg: `入参curFloorId不能为空` } });
    return;
  }
  // 现有楼层数据
  const floorContent = readFloors(floorsFile);
  const index = floorContent.floors.findIndex((floor) => {
    return floor.uid == curFloorId;
  });
  if (index == -1) {
    ctx.send({ data: { code: 300, msg: `不存在uid为${curFloorId}的楼层` } });
    return;
  }
  // 删除楼层
  floorContent.containers.splice(index, 1);
  floorContent.floors.splice(index, 1);
  writeFile(floorsFile, JSON.stringify(floorContent, null, 4));
  ctx.send({ data: { code: 200, data: { success: true } } });
};

/**
 * 移动楼层
 * @param templateId 整页模板id
 * @param curFloorId 需要移动的当前楼层id
 * @param preFloorId 移动到目标位置的前一个楼层id 如果为空表示移动到第一个位置
 * @param {*} ctx
 * @return 返回删除是否成功
 */
const onPositionFloor = async (ctx) => {
  const body = ctx.request.body;
  const { templateId, curFloorId, preFloorId } = body;
  if (!curFloorId) {
    ctx.send({ data: { code: 300, msg: `入参curFloorId不能为空` } });
    return;
  }
  if (curFloorId == preFloorId) {
    ctx.send({
      data: { code: 300, msg: `入参curFloorId和preFloorId不能相同` },
    });
    return;
  }
  // 现有楼层数据
  const floorContent = readFloors(floorsFile);
  const curIndex = floorContent.floors.findIndex((floor) => {
    return floor.uid == curFloorId;
  });
  if (curIndex == -1) {
    ctx.send({ data: { code: 300, msg: `不存在uid为${curFloorId}的楼层` } });
    return;
  }
  const curContainer = floorContent.containers[curIndex];
  const curFloor = floorContent.floors[curIndex];
  // 先删除楼层
  floorContent.containers.splice(curIndex, 1);
  floorContent.floors.splice(curIndex, 1);
  if (preFloorId != undefined) {
    const preIndex = floorContent.floors.findIndex((floor) => {
      return floor.uid == preFloorId;
    });
    if (preIndex == -1) {
      ctx.send({ data: { code: 300, msg: `不存在uid为${preFloorId}的楼层` } });
      return;
    }
    floorContent.containers.splice(preIndex + 1, 0, curContainer);
    floorContent.floors.splice(preIndex + 1, 0, curFloor);
  } else {
    // 没有传递目标位置的前一个楼层id，默认移动到第一位
    floorContent.containers.unshift(curContainer);
    floorContent.floors.unshift(curFloor);
  }

  writeFile(floorsFile, JSON.stringify(floorContent, null, 4));
  ctx.send({ data: { code: 200, data: { success: true } } });
};

module.exports = {
  onFloorContent,
  onRenderModule,
  onDeleteFloor,
  onPositionFloor,
};
